﻿using System;
using Newtonsoft.Json.Linq;
using TrinityAPI.Base;
using TrinityAPI.Base.Tools;
using TrinityAPI.Base.Models;
using Jd.Api.Request;
using Jd.Api;

namespace JingDong.Open.Platform
{
    public class CreateWaybill : IAction
    {
        public JToken Invoke(JObject dataset, params JToken[] args)
        {
            try
            {
                var request = args.Length > 0 ? args[0] as JObject : dataset.GetJsonObject("request");
                var constant = dataset.GetJsonObject("constant");
                var extendProps = request.GetJsonObject("extendProps");
                var jingdongAPIConfig = constant.GetJsonObject("jingdongAPIConfig");
                var jingdongWaybillConfig = constant.GetJsonObject("jingdongWaybillConfig");
                var courierInfo = jingdongWaybillConfig.GetJsonObject("courierInfo");

                var apiParams = extendProps.GetJsonObject("params");
                string eShopCode = extendProps.GetJsonObjectStringValue("eShopCode");
                string version = extendProps.GetJsonObjectStringValue("version");

                int packageNo = apiParams.GetJsonObjectIntValue("package_no");
                int packageTotal = apiParams.GetJsonObjectIntValue("package_total");
                var fromAddress = apiParams.GetJsonObject("fromAddress");
                var toAddress = apiParams.GetJsonObject("toAddress");
                var skuList = apiParams.GetJsonObjectList("skuList");

                string platformOrderNo = apiParams.GetJsonObjectStringValue("platformOrderNo");
                string vendorOrderCode = apiParams.GetJsonObjectStringValue("vendorOrderCode");
                string providerCode = apiParams.GetJsonObjectStringValue("providerCode");
                
                string remark = apiParams.GetJsonObjectStringValue("remark");

                string jdlUrl = jingdongWaybillConfig.GetJsonObjectStringValue("jdlUrl");
                string url = jingdongAPIConfig.GetJsonObjectStringValue("url");
                string appKey = jingdongAPIConfig.GetJsonObjectStringValue("app_key");
                string appSecret = jingdongAPIConfig.GetJsonObjectStringValue("app_secret");

                if (string.IsNullOrWhiteSpace(jdlUrl) || string.IsNullOrWhiteSpace(url) || string.IsNullOrWhiteSpace(appKey) || string.IsNullOrWhiteSpace(appSecret))
                    throw new BaseException("@0002", "");

                if (string.IsNullOrWhiteSpace(eShopCode))
                    throw new BaseException("@3004", "");

                if (string.IsNullOrWhiteSpace(platformOrderNo))
                    throw new BaseException("@5004", "");

                if (string.IsNullOrWhiteSpace(vendorOrderCode))
                    throw new BaseException("@5005", "");

                if (string.IsNullOrWhiteSpace(providerCode))
                    throw new BaseException("@5006", "");

                if (skuList == null || skuList.Count == 0)
                    throw new BaseException("@5007", "");

                if (fromAddress == null || !fromAddress.HasValues)
                    throw new BaseException("@5008", "");
                else if (string.IsNullOrWhiteSpace(fromAddress.GetJsonObjectStringValue("provinceName")))
                    throw new BaseException("@5009", "");
                else if (string.IsNullOrWhiteSpace(fromAddress.GetJsonObjectStringValue("cityName")))
                    throw new BaseException("@5010", "");
                else if (string.IsNullOrWhiteSpace(fromAddress.GetJsonObjectStringValue("countryName")))
                    throw new BaseException("@5011", "");
                else if (string.IsNullOrWhiteSpace(fromAddress.GetJsonObjectStringValue("address")))
                    throw new BaseException("@5012", "");
                else if (string.IsNullOrWhiteSpace(fromAddress.GetJsonObjectStringValue("contact")))
                    throw new BaseException("@5013", "");
                else if (string.IsNullOrWhiteSpace(fromAddress.GetJsonObjectStringValue("phone")))
                    throw new BaseException("@5014", "");
                else if (string.IsNullOrWhiteSpace(fromAddress.GetJsonObjectStringValue("mobile")))
                    throw new BaseException("@5015", "");

                string vendorCode = jingdongWaybillConfig.GetJsonObjectStringValue("vendorCode");
                string vendorName = jingdongWaybillConfig.GetJsonObjectStringValue("vendorName");
                string salePlatform = jingdongWaybillConfig.GetJsonObjectStringValue("salePlatform", "0010001");
                
                if (string.IsNullOrWhiteSpace(vendorCode))
                    throw new ConfigException("constant.jingdongWaybillConfig.vendorCode is null or empty");
                if (string.IsNullOrWhiteSpace(vendorName))
                    throw new ConfigException("constant.jingdongWaybillConfig.vendorName is null or empty");

                var courierInfoConfig = courierInfo.GetJsonObject(providerCode);
                if (courierInfoConfig == null)
                    throw new ConfigException("constant.jingdongWaybillConfig.courierInfo.{0} is null or not an object", providerCode);
                int courierType = courierInfoConfig.GetJsonObjectIntValue("type", 1);
                string branchCode = courierInfoConfig.GetJsonObjectStringValue("branchCode");
                string settlementCode = courierInfoConfig.GetJsonObjectStringValue("settlementCode");
                string templateCode = courierInfoConfig.GetJsonObjectStringValue("templateCode");
                string expressType = courierInfoConfig.GetJsonObjectStringValue("expresstype", "2");
                string payMethod = courierInfoConfig.GetJsonObjectStringValue("paymethod", "1");
                bool childMotherOrder = courierInfoConfig.GetJsonObjectBooleanValue("childMotherOrder");
                int isDocall = courierInfoConfig.GetJsonObjectIntValue("isDocall");
                if (courierType == 1 && string.IsNullOrWhiteSpace(branchCode))
                    throw new ConfigException("constant.jingdongWaybillConfig.courierInfo.{0}.branchCode is null or empty", providerCode);
                if (courierType == 2 && string.IsNullOrWhiteSpace(settlementCode))
                    throw new ConfigException("constant.jingdongWaybillConfig.courierInfo.{0}.settlementCode is null or empty", providerCode);
                if (string.IsNullOrWhiteSpace(templateCode))
                    throw new ConfigException("constant.jingdongWaybillConfig.courierInfo.{0}.templateCode is null or empty", providerCode);

                string accessToken = GetAccessToken.GetToken(eShopCode, constant);
                var client = new DefaultJdClient(url, appKey, appSecret);

                var goodsNames = new System.Text.StringBuilder();

                if (salePlatform == "0010001" && //京东平台
                    (string.IsNullOrWhiteSpace(toAddress.GetJsonObjectStringValue("contact")) || string.IsNullOrWhiteSpace(toAddress.GetJsonObjectStringValue("address"))))
                {
                    JObject orderInfo = null;
                    PopOrderGetRequest orderRequest = new PopOrderGetRequest();
                    orderRequest.orderId = platformOrderNo;
                    orderRequest.optionalFields = "orderId,venderId,orderType,consigneeInfo";
                    var orderResponse = client.Execute(orderRequest, accessToken, DateTime.Now.ToLocalTime());

                    if (!orderResponse.IsError)
                    {
                        var orderData = JSONHelper.JsonToJObject(orderResponse.Body);
                        orderInfo = orderData.GetJsonObject("jingdong_pop_order_get_responce").GetJsonObject("orderDetailInfo").GetJsonObject("orderInfo");
                    }

                    if (orderInfo == null)
                        throw new BaseException("@5016", "");

                    var consigneeInfo = orderInfo.GetJsonObject("consigneeInfo");
                    if (consigneeInfo == null)
                        throw new BaseException("@5017", "");

                    string fullname = consigneeInfo.GetJsonObjectStringValue("fullname");
                    string fullAddress = consigneeInfo.GetJsonObjectStringValue("fullAddress");
                    string province = consigneeInfo.GetJsonObjectStringValue("province");
                    string city = consigneeInfo.GetJsonObjectStringValue("city");
                    string county = consigneeInfo.GetJsonObjectStringValue("county");
                    string mobile = consigneeInfo.GetJsonObjectStringValue("mobile");
                    string oaid = consigneeInfo.GetJsonObjectStringValue("oaid");

                    toAddress = new JObject();
                    toAddress["provinceName"] = province;
                    toAddress["cityName"] = city;
                    toAddress["countryName"] = county;
                    toAddress["address"] = fullAddress;
                    toAddress["contact"] = fullname;
                    toAddress["phone"] = mobile;
                    toAddress["mobile"] = mobile;
                    toAddress["oaid"] = oaid;
                }
                
                foreach (var skuInfo in skuList)
                {
                    goodsNames.AppendFormat("{0}*{1};", skuInfo.GetJsonObjectStringValue("sku"), skuInfo.GetJsonObjectIntValue("qty"));
                }
                string cargoStr = goodsNames.ToString() + platformOrderNo;

                // 在remark显示(多包裹)
                if (packageTotal > 1 && packageNo > 0)
                {
                    cargoStr = cargoStr + string.Format("({0}/{1})", packageNo, packageTotal);
                }

                if (toAddress == null || !toAddress.HasValues)
                    throw new BaseException("@5020", "");
                else if (string.IsNullOrWhiteSpace(toAddress.GetJsonObjectStringValue("provinceName")))
                    throw new BaseException("@5021", "");
                else if (string.IsNullOrWhiteSpace(toAddress.GetJsonObjectStringValue("cityName")))
                    throw new BaseException("@5022", "");
                else if (string.IsNullOrWhiteSpace(toAddress.GetJsonObjectStringValue("countryName")))
                    throw new BaseException("@5023", "");
                else if (string.IsNullOrWhiteSpace(toAddress.GetJsonObjectStringValue("address")))
                    throw new BaseException("@5024", "");
                else if (string.IsNullOrWhiteSpace(toAddress.GetJsonObjectStringValue("contact")))
                    throw new BaseException("@5025", "");
                else if (string.IsNullOrWhiteSpace(toAddress.GetJsonObjectStringValue("phone")))
                    throw new BaseException("@5026", "");
                else if (string.IsNullOrWhiteSpace(toAddress.GetJsonObjectStringValue("mobile")))
                    throw new BaseException("@5027", "");

                var content = new JObject();
                content["waybillType"] = 1;                                             //运单类型：1普通运单
                content["waybillCount"] = 1;                                            //所需运单的数量，顺丰只能传1，非顺丰快递公司最多只能传99
                //content["providerId"] = 467;                                          //承运商id (providerId与providerCode两者必填一个)
                content["providerCode"] = providerCode;                                 //承运商编码(providerID与providerCode两者必填一个)
                content["branchCode"] = courierType == 1 ? branchCode : "";             //承运商发货网点编码  ，加盟型快递公司必传
                content["settlementCode"] = courierType == 2 ? settlementCode : "";     //财务结算编码，直营型快递公司必传
                content["salePlatform"] = salePlatform;                                 //销售平台。0010001代表京东平台下的订单  0010002天猫、t&b订单  0030001 其他平台订单
                content["platformOrderNo"] = platformOrderNo;                           //平台订单号。非京东平台填所对应平台的订单号
                content["vendorCode"] = vendorCode;                                     //商家编码，是用POP商家ID
                content["vendorName"] = vendorName;                                     //商家名称
                content["vendorOrderCode"] = vendorOrderCode;                           //商家自有订单号
                content["fromAddress"] = fromAddress;                                   //京标发货四级地址
                content["toAddress"] = toAddress;                                       //京标收货四级地址
                content["weight"] = 0;                                                  //重量，单位为千克 两位小数。没有传0
                content["volume"] = 0;                                                  //体积，单位为统一为立方厘米 两位小数。没有传0
                content["goodsName"] = goodsNames.ToString();                           //商品名称 
                content["promiseTimeType"] = 0;                                         //承诺时效类型。无时效默认传0
                //content["promiseCompleteTime"] = "";                                  //承诺完成时间，若未承诺时效，则不考虑此字段
                //content["promiseOutStockTime"] = "";                                  //计划出库时间
                content["payType"] = 0;                                                 //付款方式0-在线支付  目前暂时不支持货到付款业务
                content["goodsMoney"] = 0;                                              //商品金额  两位小数
                content["shouldPayMoney"] = 0;                                          //代收金额  两位小数  付款方式为在线支付时，代收金额必须为0
                content["needGuarantee"] = false;                                       //是否要保价（系统暂不开放报价业务）
                content["guaranteeMoney"] = 0;                                          //保价金额  两位小数  needGuarantee为false时，保价金额必须为0
                content["receiveTimeType"] = 0;                                         //收货时间类型，0任何时间，1工作日2节假日
                //content["warehouseCode"] = "";                                        //发货仓编码
                //content["secondSectionCode"] = "";                                    //二段码 京配路区
                //content["thirdSectionCode"] = "";                                     //三段码 京配站点ID
                content["remark"] = remark;                                             //备注
                content["expressPayMethod"] = payMethod;                                //快递费付款方式(顺丰必填)。1:寄方付 2:收方付 3:第三方付
                content["expressType"] = expressType;                                   //快件产品类别(顺丰必填)。1.顺丰次日   2.顺丰隔日
                content["isDocall"] = isDocall;                                         //通知收派员上门收件，目前只有顺丰使用，只有子母单模式（childMotherOrder传true）支持，1：要求 0：不要求
                content["childMotherOrder"] = childMotherOrder;                         //是否子母单，顺丰都可以为 true，其他承运商根据实际情况填写
                content["orderType"] = 1;                                               //单据类型，1:正向单 3:售后单
                //content["extendField1"] = "";                                         //扩展字段1

                string paramContent = content.ToString(Newtonsoft.Json.Formatting.None);
                LogHelper.Info("jingdong.ldop.alpha.waybill.receive request: " + paramContent);
                LdopAlphaWaybillReceiveRequest req = new LdopAlphaWaybillReceiveRequest() { content = paramContent };
                var waybillResponse = client.Execute(req, accessToken, DateTime.Now.ToLocalTime());
                LogHelper.Info("jingdong.ldop.alpha.waybill.receive response: " + waybillResponse?.Body);

                JObject waybillInfo = null;
                if (!waybillResponse.IsError)
                {
                    waybillInfo = JSONHelper.JsonToJObject(waybillResponse.Body).GetJsonObject("data");
                }

                if (waybillInfo == null)
                {
                    throw new BaseException("@5028", "");
                }

                var waybillCodes = waybillInfo.GetJsonObjectList<string>("waybillCodeList");
                if (waybillCodes == null || waybillCodes.Count == 0 || string.IsNullOrWhiteSpace(waybillCodes[0]))
                {
                    throw new BaseException("@5028", "");
                }

                string waybillData = null;
                string waybillCode = waybillCodes[0];
                string customerCode = courierType == 1 ? branchCode : settlementCode;

                JArray printData = new JArray();
                printData.Add(new JObject()
                {
                    { "carrierCode", providerCode },
                    { "billCodeType", "waybillCode" },
                    { "billCodeValue", waybillCode },
                    { "orderNumber", vendorOrderCode },
                    { "scene ", 4 },
                    { "customizedPrintData", new JObject()
                        {
                            { "cargos", cargoStr }
                        }
                    },
                    { "customerPrintData", new JObject()
                        {
                            { "productCode", "ed-m-0001" },
                            { "businessOrderId", platformOrderNo },
                            { "senderName", fromAddress.GetJsonObjectStringValue("contact") },
                            { "senderMobile", "" },
                            { "senderAddress", "******" },
                            //{ "receiverName", toAddress.GetJsonObjectStringValue("contact") },
                            //{ "receiverMobile", toAddress.GetJsonObjectStringValue("mobile") },
                            //{ "receiverAddress", toAddress.GetJsonObjectStringValue("address") },
                            { "remark", cargoStr },
                            { "weight", 1 },
                            { "packageCount", 1 },
                            { "settleType ", 0 }
                        }
                    }
                });

                JArray paramArray = new JArray();
                paramArray.Add(new JObject()
                {
                    { "taskId", Guid.NewGuid().ToString() },
                    { "templateCode", templateCode },
                    { "customerCode", vendorCode },
                    { "operator", vendorCode },
                    { "printData", printData },
                    { "outputConfig", new JObject()
                        {
                            { "outputType", 1 },
                            { "dataFormat", 2 },
                            { "fileFormat", 1 }
                        }
                    }
                });

                string method = jingdongWaybillConfig.GetJsonObjectStringValue("printmethod", "/cloud/print/render");
                string param = paramArray.ToString(Newtonsoft.Json.Formatting.None);
                string timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                string signContent = string.Format("{0}access_token{1}app_key{2}method{3}param_json{4}timestamp{5}v2.0{0}", appSecret, accessToken, appKey, method, param, timestamp);
                string sign = Utils.MD5(signContent, System.Text.Encoding.UTF8, true);
                jdlUrl = string.Format("{0}{1}?app_key={2}&access_token={3}&timestamp={4}&v=2.0&LOP-DN=jdcloudprint&sign={5}", jdlUrl, method, appKey, accessToken, timestamp, sign);

                LogHelper.Info(method + " request: " + param);
                var headers = new System.Collections.Generic.Dictionary<string, string>() { { "X-UseJosAuth", "true" } };
                string result = HttpHelper.HttpWebRequest(jdlUrl, param, "POST", 5000, headers);
                //LogHelper.Info(method + " response: " + result);

                var printDataObject = JSONHelper.JsonToJObject(result);

                int code = printDataObject.GetJsonObjectIntValue("code");

                if (code == 1000)
                {
                    var results = printDataObject.GetJsonObjectList<JObject>("result");
                    if (results != null && results.Count > 0)
                        waybillData = results[0].GetJsonObjectStringValue("base64");
                }
                else
                {
                    LogHelper.Info(method + " response: " + result);
                }

                if (string.IsNullOrWhiteSpace(waybillData))
                {
                    throw new BaseException("@5029", "");
                }

                return new JObject()
                {
                    { "waybillCode", waybillCode },
                    { "waybillData", waybillData }
                };
            }
            catch(BaseException ex)
            {
                if (!string.IsNullOrEmpty(ex.Message))
                    throw ex;
                throw new Exception(ex.Code);
            }
            catch (Exception ex)
            {
                LogHelper.Info("CreateWaybill fail: " + ex.Message);
                throw new Exception("@3001");
            }
        }
    }
}
